
export enum PatchType {
    ChangeProps = 'ChangeProps',
    Replace = 'Replace'
}
let __preNode: AutoJs.UiObject | null = null
export function diffCurrent(currentNode: AutoJs.UiObject) {
    const patches = diff(__preNode, currentNode)
    __preNode = currentNode;
    return patches;
}
export function diff(oldTree: AutoJs.UiObject | null, newTree: AutoJs.UiObject | null) {
    const patches: any[] = []
    const globalIndex = 0;
    dfsWalk(oldTree, newTree, globalIndex, patches);
    return patches;
}
function diffChildren(oldNode: AutoJs.UiObject, newNode: AutoJs.UiObject, index: number, patches: any[]) {
    const childCount = oldNode.childCount()
    for (let i = 0; i < childCount; i++) {
        try {
            index = dfsWalk(oldNode.child(i), newNode.child(i), index, patches);
        } catch (e) {
            console.log(`remove child ${i}`)
        }
    }
    return index;
}
export function dfsWalk(oldNode: AutoJs.UiObject | null, newNode: AutoJs.UiObject | null, index: number, patches: any[] = []) {
    let curPatch = [];
    let nextIndex = index + 1;
    if (!newNode) return nextIndex;
    if (!oldNode) return nextIndex;
    if (!oldNode.visibleToUser()) return nextIndex;
    if (newNode.className() === oldNode.className() && newNode.id() === oldNode.id()) {
        //节点相同，开始判断属性(未写key时都是undefined，也是相等的)
        let props = diffProps(oldNode, newNode);
        if (props.length) {
            curPatch.push({ type: PatchType.ChangeProps, props });
        }
        //如果有子树则遍历子树
        if (oldNode.childCount() > 0) {
            nextIndex = diffChildren(oldNode, newNode, nextIndex, patches);
        }
    } else {
        //节点tagName或key不同
        curPatch.push({ type: PatchType.Replace, node: newNode });
    }
    //将收集的变化添加至补丁包
    if (curPatch.length > 0) {
        if (patches[index]) {
            patches[index] = patches[index].concat(curPatch);
        } else {
            patches[index] = curPatch;
        }
    }
    //为追踪节点索引，需要将索引返回出去
    return nextIndex;
}
export interface PropPatch {
    type: 'selected' | 'visibleToUser';
    from: boolean;
    to: boolean;
}
function diffProps(oldNode: AutoJs.UiObject, newNode: AutoJs.UiObject) {
    let propPatch: PropPatch[] = [];
    const oldSelected = oldNode.selected()
    const newSelected = newNode.selected()
    if (oldSelected !== newSelected) {
        const oldText = oldNode.desc() || oldNode.text()
        const newText = newNode.desc() || newNode.text()
        if (oldText && newText && oldText === newText) {
            propPatch.push({
                type: 'selected',
                from: oldSelected,
                to: newSelected
            })
        }
    }
    return propPatch;
}
